/** ------------------------------ Tooltips object ------------------------------ **/
/**
 *  Note: DOM Utiltity and Drag and Resize units are enclosed.
 */
(function Tips(ns, undefined){
      "use strict"
      ns = ns || 'TIPS';
      var  tipContentClass  = 'tipContent'
          ,tipHeaderClass   = 'header'
          ,tipBodyClass     = 'tbody'
          ,tipElClass       = 'hastooltip'
          ,tipDataId        = 'data-tipid'
          ,tipCreateHeader  = 'data-tipheader'
          ,tipCreateText    = 'data-tiptext'
           //-> initialize DOM utility and Drag unit
          ,Utils            = DOMUtil()
          ,DResize          = DragResize(false)
          ,tipTestRE        = RegExp(tipElClass,'i')
          ,z                = 1
          ,d                = document
          ,w                = window
          ,$$               = Utils.$
          ,docbody          = d.body || d.documentElement
          ,cloneStore       = {}
          ,silentError      = true
          ,tips             = { 'create':   createTip
                               ,'refresh':  refreshTipContent
                               ,'settings': {  'silenterror': function(tf){
                                                                tf = tf && tf === 'false' ? false : true;
                                                                silentError = tf;
                                                              }
                                              ,'dragcontent': DResize
                                              ,'autofix'    : false }
                              }
      ;

      if (!document.querySelector){
            var allElements = d.getElementsByTagName('*');
            for (var i=0;i<allElements.length;(i=i+1)){
              tipTestRE.lastIndex = 0;
              if (tipTestRE.test(allElements[i].className)){
                  allElements[i].onmouseover = null;
                  allElements[i].title = 'no tooltip: upgrade your browser!';
              }
            }

            alert('Your browser doesn\'t support all of the program to show tooltips in this page. '+
                  'A browser upgrade is strongly advised.\n'+
                  'Usable browsers are: Firefox >= 4, Chrome, Opera >=10, Safari or Internet Explorer >=8.');
            return {create: function(){alert('no tooltips available: upgrade your browser');}};
      }

      /** Program **/
      function unit(unit,val){
        val = val || this || '0';
        unit = unit || 'px';
        return String(val)+unit;
      }

      Number.prototype.unit = Number.prototype.unit || unit;

      function init(fromRoot,singleMode){

         function findTip(el){
           return $$('^#'+el.id+' .'+tipContentClass);
         }

         function setHoverstate(e){
            e = e || event;
            var forEl = this.originator || this;
            var thereAreHoveredChildren = /over/i.test(e.type)
                                          ? true
                                          : /out/i.test(e.type) ? false
                                          : chkHoveredChildren(forEl);
            forEl.ishovered = thereAreHoveredChildren ? true : false;
         }

         function initOnLoad(){
           var els = $$(tipElClass.dot())
               ,i  = 0
           ;
           for(;i<els.length;i++){
            Utils.listen(els[i],'mouseover', showTip, null);
           }
         }

         function inits(fromElement,forElement){
          fromElement.id = fromElement.id || Utils.randomId();

          var els = forElement ? [fromElement] : $$('^#'+fromElement.id+' .'+tipElClass)
              ,i = 0
              ,el
              ,head;

          for(;i<els.length;i++){
             el = els[i];

             if (el.tipdone){continue;}

             /* direct creation from data-attributes */
             var createFromData = el.getAttribute(tipCreateText);
             if (createFromData){
              head = el.getAttribute(tipCreateHeader);
              var tipobj = {};
              el.className = el.className.replace(tipTestRE,'');

              if (head){
                tipobj.head = head;
              }
              tipobj.text = createFromData;
              el.removeAttribute(tipCreateHeader);
              el.removeAttribute(tipCreateText);
              createTip(el,tipobj,true);
              return true;
             }
             /* end data-attribute creation */

             var external = $$('#'+el.getAttribute(tipDataId))
                ,tip      = external ? external : findTip(el);

             if (!tip) {
               continue;
             }
             el.tip         = tip;
             el.ishovered   = false;
             tip.isopen     = false;
             tip.originator = el;
             tip.id         = tip.id || Utils.randomId();
             head           = $$('^#'+tip.id+' .'+tipHeaderClass);

             Utils.listen(el,'mouseout',hideTip,null,null);
             Utils.listen(el,'mouseover',setHoverstate,null,null);
             Utils.listen(el.tip,'mouseover',setHoverstate,null,null);
             Utils.listen(el.tip,'mouseout', setHoverstate,null,null);
             if (head){
              Utils.listen(el,'click',fixTip,true,null); //->IE <9 nobubble
              Utils.listen(head,'click'
                     ,function(){Utils.invokeHandler(el,'click');}
                     ,null);
             }
             el.tipdone = true;
           }
         }
         if (fromRoot){
           inits(fromRoot,singleMode);
         } else {
           initOnLoad();
         }
      }

      function minimize(){
        var tclone = this.parentNode.parentNode
           ,txtEl  = $$('^#'+tclone.id+' .'+tipBodyClass)
           ,header = this.parentNode
        ;
        if (/triangledown/i.test(this.className)){
          txtEl.style.position                    = '';
          txtEl.style.top                         = '';
          tclone.style.height                     = '';
          tclone.style.backgroundColor            = '';
          this.parentNode.style.borderBottomColor = '';
          txtEl.style.borderTopColor              = '';
          this.className                          = 'triangleup';
          tclone.style.height                     = '';
        } else {
          tclone.style.width                      = tclone.clientWidth.unit();
          txtEl.style.position                    = 'absolute';
          Utils.hide(txtEl);
          tclone.style.backgroundColor            = '#acaeca';
          this.parentNode.style.borderBottomColor = '#acaeca';
          txtEl.style.borderTopColor              = '#acaeca';
          this.className                          = 'triangledown';
          tclone.style.height                     =  header.clientHeight.unit();
        }
      }

      function createFixed(originalTip, originator){
        var tipclone      = originalTip.cloneNode(false) //->MAN, if true IE < 9 copies handlers too!
           ,bodytext
           ,closeImg      = d.createElement('span')
           ,minImg        = d.createElement('span')
           ,resizeImgY    = d.createElement('span')
           ,resizeImgX    = d.createElement('span')
           ,dragImg       = d.createElement('span')
           ,el
           ,head
           ,nestedtips
           ,hchildren
        ;
        tipclone.id = 'fixClone_'+ originalTip.id;
        tipclone.innerHTML = originalTip.innerHTML; //-> IE<9: get rid of all the handlers
        docbody.appendChild(tipclone);
        head                 = $$('^#'+tipclone.id+' .'+tipHeaderClass);
        tipclone.bodytext    = $$('^#'+tipclone.id+' .'+tipBodyClass);
        tipclone.head        = head;
        tipclone.bodytext.id = tipclone.bodytext.getAttribute('id') || Utils.randomId();
        tipclone.style.width = tipclone.offsetWidth.unit();
        tipclone.setAttribute('data-resizeMaxHeight',800);
        tipclone.setAttribute('data-resizeMaxWidth',800);
        tipclone.style.maxWidth  = '800px';
        tipclone.style.maxHeight = (tipclone.bodytext.scrollHeight+tipclone.head.offsetHeight).unit(); //'800px';

        nestedtips = $$('#'+tipclone.id+' .'+tipElClass);
        if (nestedtips){
         if (!nestedtips.length) {nestedtips = [nestedtips];}
         while (el = nestedtips.pop()){
          Utils.listen(el,'mouseover',showTip,null,null);
         }
        }
        head.className    += ' fix';
        dragImg.className  = 'draghandle';
        hchildren          = head.childNodes;
        closeImg.className = 'fixedcloser moreclickspace';
        closeImg.innerHTML = ' ';
        minImg.className   = 'triangleup';
        minImg.innerHTML   = '';
        dragImg.innerHTML = ' ';
        head.appendChild(minImg);
        head.appendChild(closeImg);
        head.appendChild(dragImg);

        if (tipclone.bodytext.scrollHeight+16 > tipclone.offsetHeight) {
          resizeImgY.setAttribute('data-resizeEl',tipclone.id);
          resizeImgY.className= 'resizehandleY';
          resizeImgX.setAttribute('data-resizeEl',tipclone.id);
          resizeImgX.className= 'resizehandleX';
          resizeImgX.innerHTML = '&nbsp;'
          resizeImgY.innerHTML = '&nbsp;'

          tipclone.bodytext.appendChild(resizeImgY);
          tipclone.appendChild(resizeImgX);
          tipclone.bodytext.style.marginRight = '1px';

          resizeImgY.resizehandler = function(){
           var resizeEl = $$('#'+this.getAttribute('data-resizeEl'))
              ,bodyTxt = $$('^#'+resizeEl.id+' .'+tipBodyClass)
              ,head    = $$('^#'+resizeEl.id+' .'+tipHeaderClass);
           if (bodyTxt) {
             bodyTxt.style.maxHeight = (resizeEl.clientHeight-(head.offsetHeight)).unit();
             bodyTxt.style.height = 'auto';
           }
          };
        }

        dragImg.setAttribute('data-moveEl',tipclone.id);
        head.setAttribute('data-moveEl',tipclone.id);
        createTip(
            closeImg
           ,{text:'close this box <br />(<b class="'+tipElClass+' white" '+
                  'data-tipid="closerNotes" '+
                  'data-tipwidth="300">Notes</b>)'}
           ,true);
        minImg.setAttribute('data-tipwidth',100);
        originator.fixclone = tipclone;

        Utils.listen(closeImg,'click', function(e){
          var tclone       = this.parentNode.parentNode;
          tclone.savedTop  = tclone.offsetTop || null;
          tclone.savedLft  = tclone.offsetLeft;
          Utils.hide(tclone);
          return false;
         }, null, null
        );
        tipclone.savedTop  = tipclone.offsetTop;
        tipclone.savedLeft = tipclone.offsetLeft;
        Utils.listen(minImg,'click',minimize,null, null);
        originalTip.id     = originalTip.id || Utils.randomId();
        //->store the clone for reuse
        cloneStore[tipclone.id] = $$('^#'+originalTip.id+' .'+tipHeaderClass).innerHTML;
        originalTip.blur();
        return originator.fixclone;
      }

      function findClone(forTipHeader){
         for (var l in cloneStore){
           if (cloneStore[l] === forTipHeader){
            return $$('#'+l);
           }
         }
         return null;
      }

      function fixTip(e){
        e = e || event;

        if (!this.tip){
            return true;
        }
        this.tip.id  = this.tip.id || randomId();

        var tip      = this.tip
           ,origHead = $$('^#'+this.tip.id+' .'+tipHeaderClass)
           ,created  = findClone(origHead.innerHTML) || tip.originator.fixclone
           ,tipclone = created || createFixed(tip,tip.originator)
           ,top0     = tipclone.savedTop === null ?  0 : tipclone.savedTop
           ,head     = $$('^#'+tipclone.id+' .'+tipHeaderClass)
           ,scrlTop  = docbody.scrollTop || d.documentElement.scrollTop;

        tipclone.className = tipclone.className.replace(/fadein/gi,'').replace(/^\s+|\s+$/,'');
        tipclone.style.opacity = '1.0';

        //-> restore saved position
        tipclone.style.top  = ( Number(top0) ).unit();
        tipclone.style.left = ( tipclone.savedLft || tip.offsetLeft ).unit();

        //-> scroll to fixed tip if necessary
        if (scrlTop > top0 ){
            docbody.scrollTop = d.documentElement.scrollTop = top0;
        }
        tipclone.style.zIndex = Utils.z.incr();
        if (created){
          head.style.backgroundColor = 'green';
        }
        if ($$('^#'+tipclone.id+' .triangledown')){
          setTimeout( function(){
             head.style.backgroundColor = '';
             Utils.invokeHandler($$('^#'+tipclone.id+' .triangledown'),'click');
            }
            ,500
           );
        } else {
          setTimeout( function(){
             head.style.backgroundColor = '';
            }
            ,300
           );
        }
        //->hide original tip
        tip.originator.ishovered = false;
        Utils.hide(tip);
      }

      function refreshTipContent(tipEl,nwContent,directShow){
        tipEl = tipEl.tip || tipEl;

        var head   = $$('^#'+tipEl.id+' .'+tipHeaderClass)
           ,body   = $$('^#'+tipEl.id+' .'+tipBodyClass)
           ,cloned = $$('#fixClone_'+tipEl.id)
        ;
        if (nwContent.head){
          if (!head){
            head = d.createElement('span');
            head.className = tipHeaderClass;
            tipEl.insertBefore(head,tipEl.childNodes[0]);
            Utils.listen(tipEl.originator,'click',fixTip,null,null);
            Utils.listen(head,'click',function(){Utils.invokeHandler(tipEl.originator,'click');},null,null);
          }
          head.innerHTML = nwContent.head || '?';
        }
        if (nwContent.text){
          body.innerHTML = nwContent.text;
        }
        //-> also refresh the clone (fixed tooltip)
        if (cloned){
          // ->prevent overwrite of header items (iow text refresh only)
          $$('^#'+cloned.id+' .'+tipHeaderClass).firstChild.nodeValue = nwContent.head;
          $$('^#'+cloned.id+' .'+tipBodyClass).innerHTML = nwContent.text;
          cloned.style.width = tipEl.offsetWidth.unit();
          cloned.style.height = tipEl.offsetHeight.unit();
        }
        return true;
      }

      function createTip(fromEl,obj,noInit){
        tipTestRE.lastIndex = 0;
        if (tipTestRE.test(fromEl.className)){
          return true;
        }

        fromEl.className  += ' '+tipElClass;
        var container  = d.createElement('span')
            ,head      = (obj.head ? d.createElement('span') : null)
            ,txt       = d.createElement('span')
            ,nestedTips
        ;

        container.className = tipContentClass;
        txt.className       = tipBodyClass;

        if (head) {
          head.className = tipHeaderClass;
          head.innerHTML = obj.head;
          container.appendChild(head);
        }
        container.id  = Utils.randomId();
        txt.id = Utils.randomId()
        txt.innerHTML = obj.text;
        fromEl.setAttribute(tipDataId,container.id);
        container.appendChild(txt);
        docbody.appendChild(container);
        Utils.hide(container);

        nestedTips = $$('#'+txt.id+' .'+tipElClass);
        if (nestedTips){
          nestedTips = !nestedTips.length ? [nestedTips] : nestedTips;
          for (var i=0;i<nestedTips.length;(i=i+1)){
            Utils.listen(nestedTips[i],'mouseover',showTip,null,null);
          }
        }
        Utils.listen(fromEl,'mouseover',showTip,null,null);
        //->show immediatly (!noInit) or not
        if (!noInit){
          init(fromEl,true);
          Utils.invokeHandler(fromEl,'mouseover');
        } else {
          init(fromEl,true);
        }
        return container.id;
      }

     function chkHoveredChildren(el){
       var  tip = el.tip
           ,children = tip ? $$('#'+tip.id+' .'+tipElClass) : []
           ,hasOpenChildren = false
       ;
       if (children){
         children = children.length ? children : [children];
         for (var i=0;i<children.length;(i=i+1)) {
          if (children[i].tip && (children[i].tip.originator.ishovered || children[i].tip.isopen)){
            return true;
          }
          if (children[i].tip && $$('^#'+children[i].tip.id+' .'+tipElClass)){
            hasOpenChildren = chkHoveredChildren(children[i]);
          }
         }
       }
       return hasOpenChildren;
     }

     function hideTip(e){
        e = e || event;
        var srcEl  = e.srcElement || e.target
           ,tip    = (findTipFromChild(srcEl)).tip
           ,tclose = function(){
                     var bodytxt = $$('^#'+tip.id+' .'+tipBodyClass) || {};
                     Utils.hide(tip);
                     tip.className = tip.className.replace(/fadein/gi,'fadeout').trimall();
                     tip.style.width = '';
                     bodytxt.scrollTop = 0;
                     tip.isopen = false;
            }
           ,wait   = function(){
                      var cannotclose = tip.originator.ishovered || chkHoveredChildren(tip.originator);
                      if (!cannotclose){
                       tclose();
                      } else {
                       setTimeout(wait,200);
                      }
            }
        ;
        tip.originator.ishovered = false;
        return setTimeout(wait,200);
      }

      function tipRelatedDimensions(el) {
        var  postop  = Utils.findPos(el,null)
            ,posleft = Utils.findPos(el,true)
        ;
        return {
                 top:       postop
                ,left:      posleft
                ,height:    el.offsetHeight
                ,bottom:    postop+el.offsetHeight
                ,width:     posleft+el.offsetWidth
                ,docbottom: ((w.innerHeight || d.documentElement.clientHeight)+
                             (w.pageYOffset || d.documentElement.scrollTop))-16  // 16 = scrollbar space
                ,docright:  ((w.innerWidth  || d.documentElement.clientWidth) +
                             (w.pageXOffset || d.documentElement.scrollLeft))-16
                ,tipright:  0
                ,tipbottom: 0
        };
      }

      function tipCreationError(tipEl){
       if (silentError){
        tipEl.className = tipEl.className.replace(tipElClass,'');
        tipEl.setAttribute('title','tip creation failed!'); //-> FF doesn't show it because of it's stupid bubbling shit!
        if (tipEl.removeEventListener){
          var h;
          while (h = Utils.handlerCache[tipEl.id]['mouseover'].pop()){
           tipEl.removeEventListener('mouseover',h,false);
          }
        }
        return true;
       }

        var datax = [], attribs = tipEl.attributes, attrib;
        for (var i=0;i<attribs.length; (i = i+1)){
         if (/data\-/i.test(attribs[i].name)){
           datax.push('<i>'+attribs[i].name+'</i>: "'+tipEl.getAttribute(attribs[i].name)+'"');
         }
        }
        tipEl.className = tipEl.className.replace(tipElClass,'');
        tipEl.setAttribute('data-tipwidth',300);
        var linkToTechnicalHowTo =
              ['(see also: <span class="'+tipElClass+'" ',
               'data-tipid="technical" data-tipwidth="400">',
               'techical how to</span>)'].join('');
        createTip(tipEl,{text:[ '<p>We tried to create a tooltip '
                               ,'but failed to do so, sorry. '
                               ,'Check your HTML/ECMA-code</p>'
                               ,'<p>Possible relevant attributes where:</p>'
                               ,'<p>',datax.join('<br />'),'</p>'
                               ,'<p>',linkToTechnicalHowTo,'</p>'].join('')
                         ,head: 'An error occured'},false);
        silentError = 'true'; //->reporting an error is always explicit
        return true;
      }

      function showTip(e){
        e = e || event;

        if (d.onthemove){ return false; }

        var originator = e.srcElement || e.target, head;

        var tipEl = (originator.tip || (RegExp(tipElClass,'i').test(originator.className))
                     ? originator
                     : findTipFromChild(originator));

        if (!tipEl) { return true; }

        if (!tipEl.tip) {

          init(tipEl,true);

          if (!tipEl.tip) {//->no hopes, couldn't create tooltip
            tipCreationError(tipEl);
            return true;
          }
        }

        //-> if a clone is open, show that (also if it originates from a nested element with the same tooltip)
        head = $$('^#'+tipEl.tip.id+' .'+tipHeaderClass);
        if ((tipEl.fixclone && tipEl.fixclone.offsetTop>=-10) || (head && findClone(head.innerHTML))){
           return fixTip.call(tipEl,e);
        }

        var tip    = tipEl.tip
           ,post   = Utils.findPos(tipEl,null)
           ,posl   = Utils.findPos(tipEl,true)
           ,maxw   = Math.floor((w.innerWidth  || docbody.clientWidth)/3)
           ,dims   = tipRelatedDimensions(tipEl)
           ,tipw   = Number(tipEl.getAttribute('data-tipwidth')) || null
           ,clkspce= /moreclickspace/i.test(tipEl.className)
           ,body   = $$('^#'+tip.id+'>.tbody')
        ;

        tip.scrolledup     = false;
        tip.style.width    = tipw ? tipw.unit() :
                              tip.offsetWidth > maxw
                               ? maxw.unit()
                               : tip.offsetWidth;
        tip.style.position = 'absolute';
        tip.style.left     = (dims.left-1).unit();
        tip.style.top      = (dims.top+dims.height-(clkspce ? -3 : 1)).unit();

        dims.tipbottom = Utils.findPos(tip,null) + tip.offsetHeight;
        dims.tipright  = Utils.findPos(tip,true) + tip.offsetWidth;

        if (dims.tipbottom > dims.docbottom){ //->move in sight (up)
            while ( (dims.tipbottom = Utils.findPos(tip,null) + tip.offsetHeight)
                      >= dims.top ){
             tip.style.top = ( tip.offsetTop-8 ).unit();
            }
            tip.scrolledup = true;
        }

        if (dims.tipright >= dims.docright){ //->move in sight (left)
            while ((dims.tipright = Utils.findPos(tip,true) + tip.offsetWidth)
                    >= dims.docright-8){
              tip.style.left = (tip.offsetLeft-8).unit();
            }
            if (tip.scrolledup){
              tip.style.top = (dims.top-tip.offsetHeight).unit();
            }
            //->chrome peculiarity
            if (head){
              head.style.width = '100%';
            }
            body.style.width = '100%';
        }

        if (Utils.findPos(tip,null) < (dims.top+dims.height-4) ){ //->move above originator
          tip.style.top = (dims.top-tip.offsetHeight).unit();
        }

        if (tip.offsetTop < 0){ //->move in sight (down)
          while(tip.offsetTop < 0){
            tip.style.top = (tip.offsetTop+10).unit();
          }
        }
        tip.style.zIndex = Utils.z.incr();
        tip.isopen = true;
        setTimeout(function(){
            if (/fadeout/i.test(tip.className)){
             tip.className = tip.className.replace(/fadeout/gi,'fadein').trimall();
            } else {
              tip.className += ' fadein';
            }
           },10);
        return true;
      }

      function findTipFromChild(el){
         var reTipClass = RegExp(tipElClass,'i');
         if (el.tip) {return el}
         while (el = el.parentNode){
            reTipClass.lastIndex = 0;
            if (el.tip || reTipClass.test(el.className)) {
             return el;
            }
         }
         return null;
      }

      //->initialize the whole stuff
      init(null,null);

      //->return a create method (all other methods are private)
      //  and a few setting properties
      //return tips;
      // no! we will put it in the given namespace
      w[ns] = tips;

/** ------------------------------ a few DOM utilities --------------------------------- **/
      function DOMUtil(){

        String.prototype.trimall = String.prototype.trimall ||
         function() {return this.replace(/^\s+|\s+$/,'').replace(/\s+/g,' ');}

        String.prototype.dot = String.prototype.dot ||
         function() {return '.'+this;}

        var w            = window
           ,d            = document
           ,handlerCache = {}
           ,z            =
                (function(){
                  var z = 0;
                  return {
                      incr: function(){z += 1; return z;}
                     ,toString: function(){return Number(z);}
                  };
                })()
        ;
        function hide(el){
          if (!el) {return true;}
          el.style.top = '-5000px';
        }

        function listen(el,etype,fn,nobubble,stopdefault){
            nobubble = nobubble || false;
            stopdefault = stopdefault || false;
            el.id = el.id || randomId();

            if (!handlerCache[el.id]){
              handlerCache[el.id] = {};
            }
            if (!handlerCache[el.id][etype]){
               handlerCache[el.id][etype] = [];
            }

            var fnwrap = function(e){
                  e = e || event;
                  if (nobubble) {
                    Utils.noBubbles(e);
                  }
                  if (stopdefault){
                    Utils.noDefault(e);
                  }
                  return fn.apply(el,Array.prototype.slice.call(arguments));
                }
            ;
            if (el.attachEvent) {
             el.attachEvent('on' + etype, fnwrap);
            } else {
             el.addEventListener(etype, fnwrap, false); //-> just bubble
            }
            handlerCache[el.id][etype].push(fnwrap);
        }

        function getEl(selector,root) {
          root = root || document;
          if (!selector || /nul/i.test(selector)) {return null;}
          var single  = /^\^/.test(selector)
             ,qselect = single ? 'querySelector' : 'querySelectorAll'
             ,nlist
             ,result  = []
             ,i       = 0;

          selector    = single ? selector.substr(1) : selector;
          nlist       = root[qselect](selector);

          if (nlist && (single || nlist.length === 1) ){
            return nlist.length ? nlist[0] : nlist; }

          if (nlist){
           for (;i<nlist.length;(i=i+1)){
            result.push(nlist[i]);
           }
           if (result.length){
            return result.length === 1 ? result[0] : result;
           }
          }
          return null;
        }

        function invokeHandler(el, etype){
          if (!el){return true;}
          if (el.fireEvent) {
            (el.fireEvent('on' + etype));
          }
          else {
            var evObj = d.createEvent('Events');
            evObj.initEvent(etype, true, false);
            el.dispatchEvent(evObj);
          }
        }

       function noDefault(e) {
            if (e.preventDefault){
              e.preventDefault();
            } else {
              e.returnValue = false;
            }
       }

        function noBubbles(e){
          if (e.stopPropagation){
              e.stopPropagation();

          } else {
              e.cancelBubble = true;
          }
        }

        function findPos(el,left){
          var which = left ? 'offsetLeft' : 'offsetTop'
             ,pos   = 0
             ,st    = findScrPos(el,left);
          while ( el ){
              pos += el[which] || 0;
              el = el.offsetParent;
          }
          return pos - st;
        }

        function findScrPos(el,left){
          var which = left ? 'scrollLeft' : 'scrollTop'
             ,pos   = 0;
          while( (!/body/i.test(el.tagName) && el) ){
            pos += el[which] || 0;
            el = el.parentNode;
          }
          return pos || 0;
        }

        function randomId(){
          return 'R_'+(Math.floor( Math.random()*10000 )+1000).toString(16);
        }

        function getCS(el,sProp,toInt){
          var elem = el;
          if (elem.currentStyle) {
            return toInt ? parseInt(elem.currentStyle[sProp],10) : elem.currentStyle[sProp] || 0;
          } else if (w.getComputedStyle) {
            var compStyle = w.getComputedStyle(elem, null)[sProp];
            return toInt ? parseInt(compStyle,10) : compStyle || 0;
          }
          return String(elem.style[sProp]||0);
        }

        return {
                 listen:        listen
                ,invokeHandler: invokeHandler
                ,noBubbles:     noBubbles
                ,noDefault:     noDefault
                ,findPos:       findPos
                ,randomId:      randomId
                ,getCS:         getCS
                ,hide:          hide
                ,handlerCache:  handlerCache
                ,$:             getEl
                ,z:             z
        };
      }; //-> Utils *end

      /** ------------------------------ drag object (sealed) ------------------------------ **/
      function DragResize(dragcontent){
        var currentDragbox = null
           ,d              = document
           ,w              = window
           ,docbody        = d.body || d.documentElement
           ,action
           ,savedcoords
           ,savedpos
           ,elHandle
           ,elRaw
           ,dragContent    = dragcontent
        ;

        function chkAction(el){
            var move   = elRaw.getAttribute('data-moveEl')
               ,resize = elRaw.getAttribute('data-resizeEl');
            return move || resize || false;
        }

        function dragInit(e){
          e = e || event;

          elRaw    = e.srcElement || e.target;

          if ( !chkAction(elRaw) ){
            return false; //-> solves FF not showing regular titles
          }

          var moveEl, resizeEl;

          if (!elRaw.moveEl || !elRaw.resizeEl){
            moveEl   = elRaw.getAttribute('data-moveEl') || elRaw.moveEl;
            resizeEl = elRaw.getAttribute('data-resizeEl') || elRaw.resizeEl;
            ;

            if (moveEl){
              action = 'drag';
              elRaw.moveEl = $$('#'+moveEl);
            }
            if (resizeEl){
              action = 'resize'
              elRaw.resizeEl = $$('#'+resizeEl);
            }
          }

          elHandle = elRaw.moveEl || elRaw.resizeEl || undefined;

          if (!elHandle){
            return true;
          }

          Utils.noDefault(e);

          savedcoords = savedcoords || getCoords(e,null,null);
          var elTop    = Utils.findPos(elHandle,null)
             ,elLeft   = Utils.findPos(elHandle,true)
             ,elHeight = elHandle.offsetHeight
             ,elWidth  = elHandle.offsetWidth
          ;

          if (!elHandle.dragInitDone){
            createDragBox(elHandle);
          }

          elRaw.relatedTo = elHandle;
          elHandle.style.position = 'absolute';

          if (elHandle.hoverbox.dragStarted){return true;}

          currentDragbox              = elHandle.hoverbox;
          currentDragbox.style.top    = (elTop-currentDragbox.borderWidth).unit();
          currentDragbox.style.left   = (elLeft-currentDragbox.borderWidth).unit();
          currentDragbox.style.height = elHeight.unit();
          currentDragbox.style.width  = elWidth.unit();
          currentDragbox.style.cursor = Utils.getCS(elRaw,'cursor');
          currentDragbox.coords       = [elTop,elLeft];
          currentDragbox.dragStarted  = true;
          elHandle.style.zIndex       = Utils.z.incr();
          currentDragbox.style.zIndex = Utils.z+1;

          if (elRaw.resizeEl){
            currentDragbox.maxwh =
              [ Number(elHandle.getAttribute('data-resizeMaxWidth') || docbody.clientWidth)
               ,Number(elHandle.getAttribute('data-resizeMaxHeight') || docbody.clientHeight)];
            currentDragbox.minwh = [200,100];
          }
        }

        function getCoords(e,top,left){
          top = top || d.body.scrollTop || d.documentElement.scrollTop;
          left = left || d.body.scrollLeft || d.documentElement.scrollLeft;

          var  y = e.pageY || e.clientY+top
              ,x = e.pageX || e.clientX+left
          ;
          return [y,x];
        }

        function doResize(e){

          if (!currentDragbox || elRaw.moveEl || !elRaw.resizeEl ||
               (currentDragbox.relatedTo.offsetHeight < Math.floor(currentDragbox.relatedTo.offsetHeight*0.2)
              || currentDragbox.relatedTo.offsetWidth < Math.floor(currentDragbox.relatedTo.offsetWidth*0.2)))
          { return true; }

          Utils.noDefault(e);

          d.onthemove = true; // don't trigger other tooltips whilst resizing

          var topBndry     = d.body.scrollTop || d.documentElement.scrollTop
             ,boxw         = currentDragbox.clientWidth
             ,boxh         = currentDragbox.clientHeight
             ,leftBndry    = d.body.scrollLeft || d.documentElement.scrollLeft
             ,rightBndry   = (leftBndry+d.documentElement.clientWidth)
             ,coords       = getCoords(e,topBndry,leftBndry) || savedcoords
             ,distanceY    = coords[0] - savedcoords[0]
             ,distanceX    = coords[1] - savedcoords[1]
             ,atBoundryRgt = currentDragbox.offsetLeft+currentDragbox.offsetWidth + distanceX > rightBndry
             ,atMaxHeight  = boxh+distanceY >= currentDragbox.maxwh[1]
             ,atMaxWidth   = boxw+distanceX >= currentDragbox.maxwh[0]
             ,atMinHeight  = boxh+distanceY <= 100
             ,atMinWidth   = boxw+distanceX <= 200
             ,atmax        = atMaxHeight && atMaxWidth
             ,atmin        = atMinHeight && atMinWidth
             ,direction    = /s\-/.test(Utils.getCS(elRaw,'cursor')) ? 'y' : 'x';
          ;

          //->custom post hoc resize handler
          if (elRaw.resizehandler && !elRaw.resizeHandlerDone){
            Utils.listen(elRaw,'resize',elRaw.resizehandler,null);
            elRaw.resizeHandlerDone = true;
          }

          if (direction === 'y'){
            currentDragbox.style.height =  atMaxHeight
                                           ? currentDragbox.maxwh[1].unit()
                                           : atMinHeight
                                             ? '100px'
                                             : (currentDragbox.clientHeight+distanceY).unit();
            elHandle.style.height  = (currentDragbox.offsetHeight - (currentDragbox.borderWidth*2)).unit();
            Utils.invokeHandler(elRaw,'resize');
          } else if (direction === 'x'){
            currentDragbox.style.width  =  atMaxWidth
                                           ?  currentDragbox.maxwh[1].unit()
                                           : atMinWidth
                                             ? '200px'
                                             : atBoundryRgt
                                              ? (currentDragbox.offsetWidth-16).unit()
                                              : (currentDragbox.clientWidth + distanceX).unit();
            elHandle.style.width   = (currentDragbox.offsetWidth - (currentDragbox.borderWidth*2)).unit();
            if (distanceX > 0) {
              elHandle.style.height  =   '';
            }
            currentDragbox.style.height = elHandle.clientHeight.unit();
          }

          if (atmax || atmin){
            savedcoords = coords;
            return stopResize(e);
          }

          savedcoords = coords;
          return false;
        }

        function doDrag(e){
          e = e || event;

          if (!currentDragbox || elRaw.resizeEl) {return false;}

          Utils.noDefault(e);
          d.onthemove = true; // don't trigger other tooltips whilst moving

          var topBndry     = d.body.scrollTop || d.documentElement.scrollTop
             ,leftBndry    = d.body.scrollLeft || d.documentElement.scrollLeft
             ,rightBndry   = (leftBndry+d.documentElement.clientWidth)
             ,coords       = getCoords(e,topBndry,leftBndry) || savedcoords
             ,distanceY    = coords[0]- savedcoords[0]
             ,distanceX    = coords[1]- savedcoords[1]
             ,atBoundryTop = currentDragbox.offsetTop + distanceY <= topBndry
             ,atBoundryLft = currentDragbox.offsetLeft + distanceX <= leftBndry
             ,atBoundryRgt = currentDragbox.offsetLeft+currentDragbox.offsetWidth + distanceX > rightBndry
          ;
          currentDragbox.style.top  =  atBoundryTop
                                       ? (topBndry).unit()
                                       : (currentDragbox.offsetTop+distanceY).unit();
          currentDragbox.style.left =  atBoundryLft
                                       ? (leftBndry).unit()
                                       : atBoundryRgt
                                         ? (rightBndry-currentDragbox.offsetWidth).unit()
                                         : (currentDragbox.offsetLeft+distanceX).unit();

          if (dragContent) {
           currentDragbox.relatedTo.style.top  = (currentDragbox.offsetTop+currentDragbox.borderWidth).unit();
           currentDragbox.relatedTo.style.left = (currentDragbox.offsetLeft+currentDragbox.borderWidth).unit();
          }

          savedcoords = coords;
          return false;
        }

        //->move
        function startdr(e){
          e = e || event;
          return /resize/i.test(action) ? doResize(e) : doDrag(e);
        }

        //->mouseup
        function stopdr(e){
           return /resize/i.test(action) ? stopResize(e) : stopDrag(e);
        }

        function stopResize(e){
          if (!currentDragbox){ return true; }
          var relatedTo              = currentDragbox.relatedTo;
          relatedTo.style.width      = currentDragbox.offsetWidth.unit();
          relatedTo.style.height     = (currentDragbox.offsetHeight-(currentDragbox.borderWidth*2)).unit();
          relatedTo.savedTop         = currentDragbox.offsetTop || null;
          relatedTo.savedLft         = currentDragbox.offsetLeft;
          currentDragbox.dragStarted = false;
          Utils.hide(currentDragbox);
          currentDragbox             = null;
          d.onthemove                = false;
          savedcoords                = null;
          action                     = null;
        }

        function stopDrag(e){
          if (!currentDragbox){ return true; }
          var boxtop                 = (currentDragbox.offsetTop<0
                                        ? 0
                                        : currentDragbox.offsetTop.unit())
             ,relatedTo              = currentDragbox.relatedTo;
          relatedTo.style.top        = boxtop;
          relatedTo.style.left       = currentDragbox.offsetLeft.unit();
          relatedTo.savedTop         = currentDragbox.offsetTop || '0';
          relatedTo.savedLft         = currentDragbox.offsetLeft;
          currentDragbox.dragStarted = false;
          Utils.hide(currentDragbox);
          currentDragbox             = null;
          d.onthemove                = false;
          savedcoords                = null;
          action                     = null;
        }

        function createDragBox(dragEl){
          var hoverbox          = dragEl.cloneNode(false);
          hoverbox.id           = Utils.randomId();
          hoverbox.className    = 'dragresizebox';
          docbody.appendChild(hoverbox);
          hoverbox.borderWidth  = Utils.getCS(hoverbox,'borderTopWidth',true);
          hoverbox.style.width  = dragEl.clientWidth.unit();
          hoverbox.style.height = dragEl.clientHeight.unit();
          hoverbox.style.left   = (dragEl.offsetLeft-hoverbox.borderWidth).unit();
          hoverbox.style.top    = (dragEl.offsetTop-hoverbox.borderWidth).unit();
          hoverbox.relatedTo    = dragEl;
          dragEl.hoverbox       = hoverbox;
          dragEl.dragInitDone   = true;
        }

        //-> add Utils.listeners
        if (!d.dragHandlersDone){
         Utils.listen(d,'mousedown', dragInit, null, null);
         Utils.listen(d,'mouseup',   stopdr, null, null);
         Utils.listen(d,'mousemove', startdr, null, null);
         d.dragHandlersDone = true;
        }

        return {
                 'switch': function(){dragContent = !dragContent; return this;}
                ,'toString': function(){return Number(dragContent);}
               };
      } //-> DragResize *end

})('TIPS',undefined) //->Tips *end
